﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using D3DSS.IDomain;
using D3DSS.DataContract;
using D3DSS.Model;
using System.Transactions;
using D3DSS.DataContract.QueryStatisticsOption;
using D3DSS.Enums;
using D3DSS.IRepository;
using System.Diagnostics;
using D3DSS.Utility;
using System.Threading.Tasks;
using System.Collections.Concurrent;

namespace D3DSS.Domain
{
    /// <summary>
    /// 统计领域
    /// </summary>
    public class DropStatistics : IDropStatistics
    {

        /// <summary>
        /// 统计单仓储接口
        /// </summary>
        protected IRepository<StatisticsOrderModel> StatisticsOrderRepository { get; set; }

        /// <summary>
        /// 统计项仓储接口
        /// </summary>
        protected IRepository<DropModel> DropRepository { get; set; }

        /// <summary>
        /// IoC注入构造函数
        /// </summary>
        public DropStatistics(IRepository<StatisticsOrderModel> statisticsOrderRepository, IRepository<DropModel> dropRepository)
        {
            StatisticsOrderRepository = statisticsOrderRepository;
            DropRepository = dropRepository;
        }

        /// <summary>
        /// 创建统计单
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public Response<StatisticsOrderResponse> CreateStatisticsOrder(StatisticsOrderRequest request)
        {
            Response<StatisticsOrderResponse> response = new Response<StatisticsOrderResponse>();
            response.Data = new StatisticsOrderResponse();

            response.MessageDictionary = new List<Message>();
            Message message = new Message();
            message.MessageCode = "0000";
            message.MessageContent = "服务器忙，请稍后再试！";
            response.MessageDictionary.Add(message);

            StatisticsOrderModel statisticsOrder = new StatisticsOrderModel();
            statisticsOrder.Act = (int)request.Act;
            statisticsOrder.GameRole = (int)request.GameRole;
            statisticsOrder.GameServer = (int)request.GameServer;
            statisticsOrder.RoomIP = request.RoomIP;
            statisticsOrder.RoomParentIP = request.RoomParentIP;
            statisticsOrder.MF = request.MF;
            statisticsOrder.UserID = request.UserID;
            statisticsOrder.CreateTime = DateTime.Now;

            try
            {
                response.Data.StatisticsOrderID = StatisticsOrderRepository.Add(statisticsOrder).ID;
                response.IsSuccess = true;
            }
            catch
            {
                response.Code = "0000";
            }
            return response;
        }

        /// <summary>
        /// 创建掉落统计项
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public Response<DropResponse> CreateDrop(DropRequest request)
        {
            Response<DropResponse> response = new Response<DropResponse>();

            response.MessageDictionary = new List<Message>();
            Message message = new Message();
            message.MessageCode = "0000";
            message.MessageContent = "服务器忙，请稍后再试！";
            response.MessageDictionary.Add(message);

            try
            {
                DropModel drop = new DropModel();
                drop.StatisticsOrderID = request.StatisticsOrderID;
                drop.MF = request.MF;
                drop.Nephalem = request.Nephalem;
                drop.RaraDrop = request.RaraDrop;
                drop.Level61RaraDrop = request.Level61RaraDrop;
                drop.Level62RaraDrop = request.Level62RaraDrop;
                drop.Level63RaraDrop = request.Level63RaraDrop;
                drop.LegendDrop = request.LegendDrop;
                drop.MagicDrop = request.MagicDrop;
                drop.TotalDrop = request.TotalDrop;
                drop.WhiteDrop = request.WhiteDrop;
                drop.IsExtend = request.IsExtend;
                drop.CreateTime = DateTime.Now;
                drop.RoomIP = request.RoomIP;
                drop.RoomParentIP = request.RoomParentIP;
                drop.ID = DropRepository.Add(drop).ID;


                response.IsSuccess = true;
            }
            catch
            {
                response.Code = "0000";
            }
            return response;
        }

        /// <summary>
        /// 查询统计
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public Response<QueryStatisticsResponse> QueryStatistics(QueryStatisticsRequest request)
        {
            Response<QueryStatisticsResponse> response = new Response<QueryStatisticsResponse>();

            response.MessageDictionary = new List<Message>();
            Message message = new Message();
            message.MessageCode = "0000";
            message.MessageContent = "服务器忙，请稍后再试！";
            response.MessageDictionary.Add(message);
            
            response.Data = new QueryStatisticsResponse();
            response.Data.Act = request.Act;
            response.Data.GameServer = request.GameServer;

            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();

            try
            {
                List<DropModel> allDrops = CacheManager.Get<List<DropModel>>(CacheRegion.StatisticsData, "PublicDrops");

                if (allDrops == null)
                {
                    allDrops = DropRepository.All();
                    CacheManager.Set(CacheRegion.StatisticsData, "PublicDrops", allDrops, ConfigHelper.GetAppSetting<int>("PublicDataExpireMinute"), false);
                }

                List<StatisticsOrderModel> allStatisticsOrders = CacheManager.Get<List<StatisticsOrderModel>>(CacheRegion.StatisticsData, "PublicStatisticsOrders");

                if (allStatisticsOrders == null)
                {
                    allStatisticsOrders = StatisticsOrderRepository.All();
                    CacheManager.Set(CacheRegion.StatisticsData, "PublicStatisticsOrders", allStatisticsOrders, ConfigHelper.GetAppSetting<int>("PublicDataExpireMinute"), false);
                }

                int act = (int)request.Act;
                int gameServer = (int)request.GameServer;

                //获取公共数据源
                List<StatisticsOrderModel> publicBaseStatisticsOrders = allStatisticsOrders.Where(s => s.Act == act && s.GameServer == gameServer).ToList();
                List<DropModel> publicBaseDrops = new List<DropModel>();
                publicBaseStatisticsOrders.ForEach(s =>
                {
                    publicBaseDrops.AddRange(allDrops.Where(d => d.StatisticsOrderID == s.ID));
                });

                //获取私有数据源
                List<StatisticsOrderModel> privateBaseStatisticsOrders = publicBaseStatisticsOrders.Where(s => s.UserID == request.UserID).ToList();
                List<DropModel> privateBaseDrops = new List<DropModel>();
                privateBaseStatisticsOrders.ForEach(s =>
                {
                    privateBaseDrops.AddRange(publicBaseDrops.Where(d => d.StatisticsOrderID == s.ID));
                });

                #region 处理公共统计项结果

                //处理公共常规统计项结果
                response.Data.PublicDefaultStatisticsResult = CacheManager.Get<StatisticsResult>(CacheRegion.StatisticsData, string.Format("PublicDefaultStatisticsResult_{0}_{1}", gameServer, act));
                if (response.Data.PublicDefaultStatisticsResult == null)
                {
                    response.Data.PublicDefaultStatisticsResult = new StatisticsResult();
                    response.Data.PublicDefaultStatisticsResult.MFStatisticsList = GetMFStatisticsDefaultResult(publicBaseStatisticsOrders, publicBaseDrops, false);
                    response.Data.PublicDefaultStatisticsResult.TimeStatisticsList = GetTimeStatisticsDefaultResult(publicBaseStatisticsOrders, publicBaseDrops, false);
                    response.Data.PublicDefaultStatisticsResult.RoomStatisticsList = GetRoomStatisticsDefaultResult(publicBaseStatisticsOrders, publicBaseDrops, false);
                    CacheManager.Set(CacheRegion.StatisticsData, string.Format("PublicDefaultStatisticsResult_{0}_{1}", gameServer, act), response.Data.PublicDefaultStatisticsResult, ConfigHelper.GetAppSetting<int>("PublicDataExpireMinute"), false);
                }
                //处理公共扩展项统计结果
                response.Data.PublicExtendStatisticsResult = CacheManager.Get<StatisticsResult>(CacheRegion.StatisticsData, string.Format("PublicExtendStatisticsResult_{0}_{1}", gameServer, act));
                if (response.Data.PublicExtendStatisticsResult == null)
                {
                    response.Data.PublicExtendStatisticsResult = new StatisticsResult();
                    response.Data.PublicExtendStatisticsResult.MFStatisticsList = GetMFStatisticsDefaultResult(publicBaseStatisticsOrders, publicBaseDrops, true);
                    response.Data.PublicExtendStatisticsResult.TimeStatisticsList = GetTimeStatisticsDefaultResult(publicBaseStatisticsOrders, publicBaseDrops, true);
                    response.Data.PublicExtendStatisticsResult.RoomStatisticsList = GetRoomStatisticsDefaultResult(publicBaseStatisticsOrders, publicBaseDrops, true);
                    CacheManager.Set(CacheRegion.StatisticsData, string.Format("PublicExtendStatisticsResult_{0}_{1}", gameServer, act), response.Data.PublicExtendStatisticsResult, ConfigHelper.GetAppSetting<int>("PublicDataExpireMinute"), false);
                }

                #endregion

                #region 处理私有统计项结果

                //处理私有常规统计项结果
                response.Data.PrivateDefaultStatisticsResult = CacheManager.Get<StatisticsResult>(CacheRegion.StatisticsData, request.UserID + string.Format("_Default_{0}_{1}", gameServer, act));
                if (response.Data.PrivateDefaultStatisticsResult == null)
                {
                    response.Data.PrivateDefaultStatisticsResult = new StatisticsResult();
                    response.Data.PrivateDefaultStatisticsResult.MFStatisticsList = GetMFStatisticsDefaultResult(privateBaseStatisticsOrders, privateBaseDrops, false);
                    response.Data.PrivateDefaultStatisticsResult.TimeStatisticsList = GetTimeStatisticsDefaultResult(privateBaseStatisticsOrders, privateBaseDrops, false);
                    response.Data.PrivateDefaultStatisticsResult.RoomStatisticsList = GetRoomStatisticsDefaultResult(privateBaseStatisticsOrders, privateBaseDrops, false);
                    CacheManager.Set(CacheRegion.StatisticsData, request.UserID + string.Format("_Default_{0}_{1}", gameServer, act), response.Data.PrivateDefaultStatisticsResult, ConfigHelper.GetAppSetting<int>("UserDataExpireMinute"), false);
                }
                //处理私有扩展项统计结果
                response.Data.PrivateExtendStatisticsResult = CacheManager.Get<StatisticsResult>(CacheRegion.StatisticsData, request.UserID + string.Format("_Extend_{0}_{1}", gameServer, act));
                if (response.Data.PrivateExtendStatisticsResult == null)
                {
                    response.Data.PrivateExtendStatisticsResult = new StatisticsResult();
                    response.Data.PrivateExtendStatisticsResult.MFStatisticsList = GetMFStatisticsDefaultResult(privateBaseStatisticsOrders, privateBaseDrops, true);
                    response.Data.PrivateExtendStatisticsResult.TimeStatisticsList = GetTimeStatisticsDefaultResult(privateBaseStatisticsOrders, privateBaseDrops, true);
                    response.Data.PrivateExtendStatisticsResult.RoomStatisticsList = GetRoomStatisticsDefaultResult(privateBaseStatisticsOrders, privateBaseDrops, true);
                    CacheManager.Set(CacheRegion.StatisticsData, request.UserID + string.Format("_Extend_{0}_{1}", gameServer, act), response.Data.PrivateExtendStatisticsResult, ConfigHelper.GetAppSetting<int>("UserDataExpireMinute"), false);
                }
                #endregion

                response.IsSuccess = true;
            }
            catch
            {
                response.Code = "0000";
            }

            stopwatch.Stop();
            response.Data.QueryTime = stopwatch.ElapsedMilliseconds;
            return response;
        }

        #region 获取统计项

        /// <summary>
        /// 获取房间号统计项结果
        /// </summary>
        /// <param name="statisticsOrders"></param>
        /// <param name="drops"></param>
        /// <returns></returns>
        protected List<RoomStatistics> GetRoomStatisticsDefaultResult(List<StatisticsOrderModel> statisticsOrders, List<DropModel> drops, bool isExtend)
        {
            var roomStatisticsList = new ConcurrentBag<RoomStatistics>();

            Parallel.For(0, 254, (roomParentIP) =>
            {
                Parallel.For(0, 254, (roomIP) =>
                {
                    var dropsPart = drops.Where(d => d.RoomIP == roomIP && d.RoomParentIP == roomParentIP && d.IsExtend == isExtend).ToList();
                    if (dropsPart != null && dropsPart.Count > 0)
                    {
                        long raraDrop = 0;
                        double level61RaraDrop = 0;
                        double level62RaraDrop = 0;
                        double level63RaraDrop = 0;

                        long totalDrop = 0;
                        double whiteDrop = 0;
                        double magicDrop = 0;
                        double legendDrop = 0;

                        dropsPart.ForEach(d => { raraDrop += d.RaraDrop; });

                        RoomStatistics roomStatistics = new RoomStatistics();
                        roomStatistics.RoomIP = roomIP;
                        roomStatistics.RoomParentIP = roomParentIP;

                        if (!isExtend)
                        {

                            dropsPart.ForEach(d => { level61RaraDrop += d.Level61RaraDrop; });
                            dropsPart.ForEach(d => { level62RaraDrop += d.Level62RaraDrop; });
                            dropsPart.ForEach(d => { level63RaraDrop += d.Level63RaraDrop; });

                            roomStatistics.Level61RaraDropRate = raraDrop == 0 ? 0 : (level61RaraDrop / raraDrop);
                            roomStatistics.Level62RaraDropRate = raraDrop == 0 ? 0 : (level62RaraDrop / raraDrop);
                            roomStatistics.Level63RaraDropRate = raraDrop == 0 ? 0 : (level63RaraDrop / raraDrop);

                            roomStatistics.Sample = raraDrop;
                        }
                        else
                        {
                            dropsPart.ForEach(d => { totalDrop += d.TotalDrop; });
                            dropsPart.ForEach(d => { whiteDrop += d.WhiteDrop; });
                            dropsPart.ForEach(d => { magicDrop += d.MagicDrop; });
                            dropsPart.ForEach(d => { legendDrop += d.LegendDrop; });

                            roomStatistics.WhiteDropRate = totalDrop == 0 ? 0 : (whiteDrop / totalDrop);
                            roomStatistics.MagicDropRate = totalDrop == 0 ? 0 : (magicDrop / totalDrop);
                            roomStatistics.RaraDropRate = totalDrop == 0 ? 0 : (raraDrop / totalDrop);
                            roomStatistics.LegendDropRate = totalDrop == 0 ? 0 : (legendDrop / totalDrop);

                            roomStatistics.Sample = totalDrop;
                        }

                        roomStatisticsList.Add(roomStatistics);
                    }
                });
            });

            return roomStatisticsList.OrderBy(r => r.RoomIP).ToList();
        }

        /// <summary>
        /// 获取时间线统计项结果
        /// </summary>
        /// <param name="statisticsOrders"></param>
        /// <param name="drops"></param>
        /// <returns></returns>
        protected List<TimeStatistics> GetTimeStatisticsDefaultResult(List<StatisticsOrderModel> statisticsOrders, List<DropModel> drops, bool isExtend)
        {
            var timeStatisticsList = new ConcurrentBag<TimeStatistics>();

            Parallel.For(0, 23, (hour) => {

                int startHour = hour;
                int endHour = hour == 23 ? 0 : (hour + 1);

                var dropsPart = drops.Where(d => d.CreateTime.Hour >= startHour && d.CreateTime.Hour < endHour).ToList();
                if (dropsPart != null && dropsPart.Count > 0)
                {
                    long raraDrop = 0;
                    double level61RaraDrop = 0;
                    double level62RaraDrop = 0;
                    double level63RaraDrop = 0;

                    long totalDrop = 0;
                    double whiteDrop = 0;
                    double magicDrop = 0;
                    double legendDrop = 0;

                    dropsPart.ForEach(d => { raraDrop += d.RaraDrop; });

                    TimeStatistics timeStatistics = new TimeStatistics();

                    timeStatistics.StartHour = startHour;
                    timeStatistics.EndHour = endHour;

                    if (!isExtend)
                    {
                        dropsPart.ForEach(d => { level61RaraDrop += d.Level61RaraDrop; });
                        dropsPart.ForEach(d => { level62RaraDrop += d.Level62RaraDrop; });
                        dropsPart.ForEach(d => { level63RaraDrop += d.Level63RaraDrop; });

                        timeStatistics.Level61RaraDropRate = raraDrop == 0 ? 0 : (level61RaraDrop / raraDrop);
                        timeStatistics.Level62RaraDropRate = raraDrop == 0 ? 0 : (level62RaraDrop / raraDrop);
                        timeStatistics.Level63RaraDropRate = raraDrop == 0 ? 0 : (level63RaraDrop / raraDrop);

                        timeStatistics.Sample = raraDrop;
                    }
                    else
                    {
                        dropsPart.ForEach(d => { totalDrop += d.TotalDrop; });
                        dropsPart.ForEach(d => { whiteDrop += d.WhiteDrop; });
                        dropsPart.ForEach(d => { magicDrop += d.MagicDrop; });
                        dropsPart.ForEach(d => { legendDrop += d.LegendDrop; });

                        timeStatistics.WhiteDropRate = totalDrop == 0 ? 0 : (whiteDrop / totalDrop);
                        timeStatistics.MagicDropRate = totalDrop == 0 ? 0 : (magicDrop / totalDrop);
                        timeStatistics.RaraDropRate = totalDrop == 0 ? 0 : (raraDrop / totalDrop);
                        timeStatistics.LegendDropRate = totalDrop == 0 ? 0 : (legendDrop / totalDrop);

                        timeStatistics.Sample = totalDrop;
                    }
                    timeStatisticsList.Add(timeStatistics);
                }
            });

            return timeStatisticsList.OrderBy(t => t.StartHour).ToList();
        }

        /// <summary>
        /// 获取MF统计项结果
        /// </summary>
        /// <param name="statisticsOrders"></param>
        /// <param name="drops"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        protected List<MFStatistics> GetMFStatisticsDefaultResult(List<StatisticsOrderModel> statisticsOrders, List<DropModel> drops, bool isExtend)
        {
            var mfStatisticsList = new ConcurrentBag<MFStatistics>();

            Parallel.For(0, 5, (mf) =>
            {
                int minMF = 75 * mf;
                int maxMF = 75 * (mf + 1);

                var dropsPart = drops.Where(d => d.MF >= minMF && d.MF < maxMF).ToList();
                if (dropsPart != null && dropsPart.Count > 0)
                {
                    long raraDrop = 0;
                    double level61RaraDrop = 0;
                    double level62RaraDrop = 0;
                    double level63RaraDrop = 0;

                    long totalDrop = 0;
                    double whiteDrop = 0;
                    double magicDrop = 0;
                    double legendDrop = 0;

                    dropsPart.ForEach(d => { raraDrop += d.RaraDrop; });

                    MFStatistics mfStatistics = new MFStatistics();

                    mfStatistics.MinMF = minMF;
                    mfStatistics.MaxMF = maxMF;

                    if (!isExtend)
                    {
                        dropsPart.ForEach(d => { level61RaraDrop += d.Level61RaraDrop; });
                        dropsPart.ForEach(d => { level62RaraDrop += d.Level62RaraDrop; });
                        dropsPart.ForEach(d => { level63RaraDrop += d.Level63RaraDrop; });

                        mfStatistics.Level61RaraDropRate = raraDrop == 0 ? 0 : (level61RaraDrop / raraDrop);
                        mfStatistics.Level62RaraDropRate = raraDrop == 0 ? 0 : (level62RaraDrop / raraDrop);
                        mfStatistics.Level63RaraDropRate = raraDrop == 0 ? 0 : (level63RaraDrop / raraDrop);

                        mfStatistics.Sample = raraDrop;
                    }
                    else
                    {
                        dropsPart.ForEach(d => { totalDrop += d.TotalDrop; });
                        dropsPart.ForEach(d => { whiteDrop += d.WhiteDrop; });
                        dropsPart.ForEach(d => { magicDrop += d.MagicDrop; });
                        dropsPart.ForEach(d => { legendDrop += d.LegendDrop; });

                        mfStatistics.WhiteDropRate = totalDrop == 0 ? 0 : (whiteDrop / totalDrop);
                        mfStatistics.MagicDropRate = totalDrop == 0 ? 0 : (magicDrop / totalDrop);
                        mfStatistics.RaraDropRate = totalDrop == 0 ? 0 : (raraDrop / totalDrop);
                        mfStatistics.LegendDropRate = totalDrop == 0 ? 0 : (legendDrop / totalDrop);

                        mfStatistics.Sample = totalDrop;
                    }

                    mfStatisticsList.Add(mfStatistics);
                }
            });

            return mfStatisticsList.OrderBy(m => m.MinMF).ToList();
        }

        #endregion

    }
}
